import type { App, Directive } from 'vue';

const DISTANCE = 150;
const DURATION = 500;

const animationMap = new WeakMap<HTMLElement, Animation>();
const ob = new IntersectionObserver((entries) => {
  for (const entry of entries) {
    if (entry.isIntersecting) {
      const animation = animationMap.get(entry.target as HTMLElement);
      animation?.play();
      ob.unobserve(entry.target);
    }
  }
});

function isBelowViewport(el: HTMLElement) {
  const rect = el.getBoundingClientRect();
  return rect.top > window.innerHeight;
}

const slideInDirective: Directive = {
  mounted(el: HTMLElement) {
    if (!isBelowViewport(el)) return;
    const animation = el.animate(
      [
        {
          transform: `translateY(${DISTANCE}px)`,
          opacity: 0.5,
        },
        {
          transform: `translateY(0)`,
          opacity: 1,
        },
      ],
      { duration: DURATION, easing: 'ease' },
    );
    animation.pause();
    animationMap.set(el, animation);
    ob.observe(el);
  },
  unmounted(el: HTMLElement) {
    ob.unobserve(el);
  },
};

export function setupSlideInDirective(app: App) {
  app.directive('slide-in', slideInDirective);
}

export default slideInDirective;
